/**
	@file
	Contains kernel entry point and some peripherals.
	@note Now used for testing.
	
	@author Konstantin Kastanov
*/
#include "main.h"
#include "api/headers/io.h"
#include "api/headers/colours.h"
#include "tools/headers/common.h"
#include "memory/headers/gdt.h"
#include "memory/headers/paging.h"
#include "interrupts/headers/idt.h"
#include "multitasking/headers/timer.h"
#include "io/headers/keyboard.h"
#include "memory/headers/kheap.h"
#include "multitasking/headers/task.h"
#include "adt/headers/queue.h"
#include "adt/headers/linked_list.h"
#include "api/headers/errors.h"
#include "fileSystem/headers/initialization.h"
#include "interface/headers/shell.h"
#include "multitasking/headers/process_killer.h"

#define ENABLE_FILE_SYSTEM false

extern u32int placement_address;
extern task_t *current_task;
extern page_directory_t* kernel_directory;
extern page_directory_t* current_directory;
u32int initial_esp;
u32int global_int = 0;
void iterate(char init)
{
	int i, a;
	for(;;)
	{
		for(i = 0; i < 10; i++)
		{
			printf("%c", init + i);
			for(a=0; a < 2000000; a++);
		}
	}
}


/**
	Kernel entry point.
*/
extern u32int timer_ticks;

int kernel_main(struct multiboot *mboot, u32int stack)
{
	FileDescriptor file;
	char filePath[] = "a:/docume~1/help.txt";
	u8int* buff;
  initial_esp = stack;
  clearScreen();
  printf("Kernel booted v1.1\n");
  
   if(mboot->mods_count > 0)
   {
	  printf("Loaded %d module(s)\n", mboot->mods_count);
	  placement_address = *(u32int*)(mboot->mods_addr + 4);
	  printf("Initial placement address: 0x%H\n", placement_address);
	  printf("Modules start at: 0x%h\n", *((u32int*)mboot->mods_addr));
   }
  initGdt();
  printf("Gdt initialized\n");
  init_idt();
  printf("Idt initialized\n");
  asm volatile("sti");
  printf("Interrupts enabled\n");
  printf("Memory passed: 0x%h\n", mboot->mem_upper * 1024);
  initialise_paging(mboot->mem_upper * 1024);
  printf("Paging initialized\nPlacement addres: 0x%H\n", placement_address);
  init_timer(100);
  printf("Timer initialized\n");
  install_keyboard();
  printf("Keyboard initialized\n");

  initialise_tasking();
  printf("Multitasking initialized. Running process: %d\n", current_task->id);
  
// 	buff = (u8int*)kmalloc(500);
// 	printf("895 addr: 0x%H\n 896 addr: 0x%H\n", current_directory->tables[895], current_directory->tables[896]);

  if((mboot->mods_count > 0) && ENABLE_FILE_SYSTEM)
  {
	printf("Initializing file system\n");
	initializeFileSystem(*((u32int*)mboot->mods_addr), *(u32int*)(mboot->mods_addr+4));
	if(getLastError() != NO_ERROR)
	{
		printf("File system error: %s\n", getLastErrorMessage());
	}
	else
	{
		getDirectoryFromPath(filePath, &file, true);
// 		printf("Name: %s\nExtension: %s\nIs directory: %d\n"
// 				"Is hidden: %d\nIs read only: %d\nIs system: %d\n"
// 				"Starting cluster: 0x%H\nFile size (Bytes): %d\n\n",
// 				file.name, file.extension, file.isDirectory,
// 				file.isHidden, file.isReadOnly, file.isSystem,
// 				file.startingCluster, file.size
// 				);
		getFileList(filePath, buff);
		if(getLastError() != NO_ERROR)
		{
			printf("Error reading file list: %s\n", getLastErrorMessage());
		}
		else
		{
			printf("Files: \n%s\n\n", buff);
		}
		
		int loaded = loadFile(&file, (u8int*)buff);

		if(getLastError() != NO_ERROR)
			printf("File loading failed: %s\n\n", getLastErrorMessage());
		else
		{
			printf("Loaded (Bytes): %d\n\n", loaded);
			buff[loaded] = 0;
			printf("File content: \n\n%s", buff);
		}
	}
  }
//   kfree(buff);
//   printf("Multiboot info:\n");
//   printf("Lower memory: %d\nUpper memory: %d\nMods count: %d\n"
// 		 "Mods addr: 0x%h\nSize: 0x%h\nAddr: 0x%h\n",
// 		 mboot->mem_lower, mboot->mem_upper, mboot->mods_count,
// 		 mboot->mods_addr, mboot->size, mboot->addr);
  
  
  putString("Operating System has been loaded.\n");
  
  


     int addr, ret;
// 	queue_type* queue = create_queue(5);
// 	for(ret = 0; ret < 3; ret++)
// 		enqueue(ret, queue);
// 	while(!queue_is_empty(queue))
// 		printf("%d ", dequeue(queue));
// 	printf("\nWith overflow\n");
// 	for(ret = 0; ret < 8; ret++)
// 		enqueue(ret, queue);
// 	while(!queue_is_empty(queue))
// 		printf("%d ", dequeue(queue));
    
	ret = fork();
	if(getLastError() != NO_ERROR)
	{
		K_PANIC("Failed to launch shell");
	}
	asm volatile("sti");
	if(ret == 0)
	{
		init_shell();
		run_shell();
	}
	else
	{
		ret = fork();
		if(getLastError() != NO_ERROR)
		{
			K_PANIC("Failed to launch process killer");
		}
		if(ret == 0)
		{
			process_killer();
		}
		else
		{
			printf("Entering infinite loop");
		}
	}
 
 for(;;);
 

  return 0;
} 


